package com.bcx.wind.workflow.imp.cmd.corecmd;

import com.bcx.wind.workflow.access.QueryFilter;
import com.bcx.wind.workflow.core.constant.TaskStatus;
import com.bcx.wind.workflow.core.constant.WorkflowOperate;
import com.bcx.wind.workflow.core.flow.NodeModel;
import com.bcx.wind.workflow.entity.*;
import com.bcx.wind.workflow.errorcontext.WindError;
import com.bcx.wind.workflow.message.MessageHelper;
import com.bcx.wind.workflow.pojo.Task;
import com.bcx.wind.workflow.pojo.Wind;
import com.bcx.wind.workflow.pojo.WindUser;
import com.bcx.wind.workflow.pojo.variable.RevokeVariable;
import com.bcx.wind.workflow.support.Assert;
import com.bcx.wind.workflow.support.JsonHelper;
import com.bcx.wind.workflow.support.ObjectHelper;

import java.util.List;
import java.util.stream.Collectors;

import static com.bcx.wind.workflow.access.AccessSqlConstant.BUSINESS_ID;
import static com.bcx.wind.workflow.access.AccessSqlConstant.ORDER_ID;
import static com.bcx.wind.workflow.core.constant.Constant.WIND_ADMIN;
import static com.bcx.wind.workflow.message.ErrorCode.*;

/**
 * <p>
 * 撤销命令
 *
 * 撤销到指定的操作ID   ,回滚到该操作id时的流程状态，流程的实例，任务，审批人。保存撤销历史
 *
 *
 * </p>
 *
 * @author zhanglei
 */
public class RevokeCommand extends BaseCommand {

    private RevokeVariable variable;

    private static final String REVOKE_ID = "revokeId";

    /**
     * 需要撤销到的记录
     */
    private WindRevokeData windRevokeData;

    public RevokeCommand(RevokeVariable variable){
        this.variable = variable;
    }


    @Override
    public Wind execute() {
        //操作
        wind().setOperate(WorkflowOperate.revoke);

        //校验参数
        checkVariable();

        //构建流程执行实例
        initWind();

        //构建当前节点
        curNode();

        //执行撤销操作
        revoke();
        return wind();
    }


    @SuppressWarnings("unchecked")
    private void revoke() {
        //流程实例信息
        String orderContent = this.windRevokeData.getWindOrder();
        //任务实例信息
        String taskContent = this.windRevokeData.getWindTask();
        //任务审批人信息
        String taskActorContent = this.windRevokeData.getWindTaskActor();

        //删除当前流程下所有的执行数据，包含流程实例，任务实例，任务所有审批人
        String orderId = wind().getWindOrder().getId();
        this.commandContext.access().removeOrderInstanceById(orderId);
        this.commandContext.access().removeOrderInstanceByParentId(orderId);

        QueryFilter filter = new QueryFilter()
                .setOrderId(orderId);
        List<String> taskIds = this.commandContext.access().selectTaskInstanceList(filter)
                .stream().map(WindTask::getId).collect(Collectors.toList());

        this.commandContext.access().removeTaskActorByTaskIds(taskIds);
        this.commandContext.access().removeTaskByOrderId(orderId);


        //解析撤销数据，重新添加
        if(!ObjectHelper.isEmpty(orderContent)){
            List<WindOrder> orders = JsonHelper.parseJson(orderContent,List.class,WindOrder.class);
            for(WindOrder windOrder : orders) {
                this.commandContext.access().insertOrderInstance(windOrder);
            }
        }

        if(!ObjectHelper.isEmpty(taskContent)){
            List<WindTask>  tasks = JsonHelper.parseJson(taskContent,List.class,WindTask.class);
            for(WindTask task : tasks){
                this.commandContext.access().insertTaskInstance(task);
            }
        }

        if (!ObjectHelper.isEmpty(taskActorContent)) {
            List<WindTaskActor> actors = JsonHelper.parseJson(taskActorContent,List.class,WindTaskActor.class);
            this.commandContext.access().insertTaskActor(actors);
        }
    }


    private void curNode(){
        List<WindTask> tasks = wind().getAllTasks();
        for(WindTask windTask : tasks){
            Task task = buildCurNodeConfig(windTask.getTaskName(),windTask);
            //构建revokeData
            if(task != null) {
                task.setRevokeTask(revokeTask());
                wind().getCurNode().add(task);
            }
        }
    }


    private Task revokeTask(){
        String taskName = this.windRevokeData.getTaskName();
        NodeModel nodeModel = wind().getWindProcess().processModel().getTaskModel(taskName);
        WindProcessConfig config = ObjectHelper.getNodeConfig(this.configList,taskName,wind().getArgs());
        return new Task()
                .setNodeId(taskName)
                .setNodeName(nodeModel.nodeName())
                .setConfig(buildWindConfig(config))
                .setTaskNode(nodeModel);
    }


    private void initWind(){
        //流程实例
        String orderId = this.variable.getOrderId();
        WindOrder windOrder = buildWindOrder(orderId);

        //流程定义
        WindProcess windProcess = this.commandContext.repositoryService().queryById(windOrder.getProcessId());
        Assert.notEmptyError(PROCESS_QUERY_NULL,windProcess,windOrder.getProcessId());

        //所有配置
        getConfigList(windProcess.getId());

        //流程实例下所有任务
        QueryFilter filter = new QueryFilter()
                .setOrderId(orderId)
                .setStatus(TaskStatus.run.name());
        List<WindTask> allTasks = this.commandContext.access().selectTaskInstanceList(filter);
        Assert.notEmptyError(NOT_FOUND_TASK,allTasks);

        wind().setArgs(this.variable.getArgs())
                .setWindOrder(windOrder)
                .setBusinessId(windOrder.getBusinessId())
                .setAllTasks(allTasks)
                .setOperator(user().getUserId())
                .setSuggest(variable.getSuggest())
                .setSubmitNode(this.windRevokeData.getTaskName())
                .setSystem(variable.getSystem())
                .setUser(user())
                .setWindProcess(windProcess)
                .setWindConfig(buildWindConfig(buildProcessConfig()));
    }


    private void checkVariable(){
        //流程实例号 或 业务ID
        String businessId = this.variable.getBusinessId();
        String orderId = this.variable.getOrderId();
        Assert.isTrueError(REVOKE_FAIL,ObjectHelper.allEmpty(businessId,orderId),BUSINESS_ID+" or "+ORDER_ID);

        //校验orderId是否存在
        if(!ObjectHelper.isEmpty(businessId)){
            QueryFilter filter = new QueryFilter()
                    .setBusinessId(businessId);
            List<WindOrder> orderList = this.commandContext.access().selectOrderInstanceList(filter);
            if(!ObjectHelper.isEmpty(orderList)){
                orderId = orderList.get(0).getId();
            }
        }
        Assert.isTrueError(REVOKE_FAIL,ObjectHelper.allEmpty(businessId,orderId),BUSINESS_ID+" or "+ORDER_ID);


        //查询撤销历史
        QueryFilter filter = new QueryFilter()
                .setOrderId(orderId);
        List<WindRevokeData> revokeData = this.commandContext.access().selectRevokeData(filter);
        Assert.notEmptyError(REVOKE_NOT_FOUND_HIST,revokeData);

        //撤销ID
        String histId = this.variable.getHistId();
        if(ObjectHelper.isEmpty(histId)){
            this.windRevokeData = revokeData.stream().findFirst()
                    .orElseThrow(()->WindError.error(MessageHelper.getMsg(REVOKE_NOT_FOUND_HIST)));
        }else{
            this.windRevokeData = revokeData.stream().filter(re->re.getId().equals(histId))
                    .findFirst().orElseThrow(()->WindError.error(MessageHelper.getMsg(REVOKE_NOT_FOUND_HIST)));
        }

        this.variable.setOrderId(orderId);
    }



    /**
     * 当前流程配置
     */
    private WindProcessConfig buildProcessConfig(){
        String processName = wind().getWindProcess().getProcessName();
        WindProcessConfig processConfig = ObjectHelper.getNodeConfig(this.configList,processName,this.variable.getArgs());
        Assert.notEmptyError(PROCESS_CONFIG_NOT_FOUND,processConfig,processName,processName);
        return processConfig;
    }



    /**
     * 当前用户  默认使用 wind_admin
     * @return  当前用户
     */
    private WindUser user(){
        WindUser user = this.variable.getUser();
        if(user == null){
            user = new WindUser()
                    .setUserId(WIND_ADMIN)
                    .setUserName("管理员");
        }
        return user;
    }
}
